package org.emergent.lucidity.test;

import java.io.IOException;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.util.encoders.Hex;
import org.emergent.lucidity.lucifer.client.LuciferImpl;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;

public class RhinoLucifer extends LucidScriptableObject
{
    static
    {
        Security.addProvider(new BouncyCastleProvider());
    }

    // The zero-argument constructor used by Rhino runtime to create instances
    public RhinoLucifer() { }

    // Method jsConstructor defines the JavaScript constructor
    public void jsConstructor() {}

    private String formatAsVar(byte[] bytes)
    {
        StringBuffer buf = new StringBuffer();
        String hexstr = new String( Hex.encode( bytes ) );
        for (int ii = 0; ii < hexstr.length(); ii += 2)
        {
            if (ii % 16 == 0)
                buf.append( "\n" );
            buf.append( "\"\\u00" );
            buf.append( hexstr.substring( ii, ii + 2 ));
            buf.append( '\"' );
            buf.append( ", " );
        }
        return buf.toString();
    }
    
    public String jsFunction_decryptString(boolean pgpcfb,int mode,String ciphertext,String keystr,String ivstr)
    {
        try {
            return LuciferImpl.decryptString( pgpcfb, (byte)mode, ciphertext, keystr, ivstr );
        }
        catch (RuntimeException e)
        {
            e.printStackTrace(  );
        }
        return null;
    }


    public String jsFunction_expandString(int method, String input) throws IOException, PGPException
    {
        return LuciferImpl.expandString( (byte)method, input );
    }

    public String execimpl(int mode,String ciphertext,String keystr,String ivstr) throws IOException, PGPException
    {
        String padstr = "/CFB/NoPadding";
        if (mode == 1)
            padstr = "/OpenPGPCFB/NoPadding";

        Cipher c = null;
        String cName = "CAST5";
        String provider = "BC";

        try
        {
            byte[] ivBytes = LuciferImpl.string2bytes( ivstr );
            byte[] keyBytes = LuciferImpl.string2bytes( keystr );
            byte[] encData = LuciferImpl.string2bytes( ciphertext );
            SecretKey key = new SecretKeySpec(keyBytes, cName);
            c = Cipher.getInstance(cName + padstr, provider);
            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
            c.init(Cipher.DECRYPT_MODE, key, ivSpec);
            byte[] data = c.doFinal(encData, 0, encData.length);
//            System.out.println( "var ivbytes = [" + formatAsVar( ivBytes ));
//            System.out.println( "var keybytes = [" + formatAsVar( keyBytes ));
//            System.out.println( "var encbytes = [" + formatAsVar( encData ));
//            System.out.println( "var expected = [" + formatAsVar( data ));
            return LuciferImpl.bytes2string( data );
        }
        catch (Exception e)
        {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public static void inject(Context cx, Scriptable scope) throws Exception
    {
        defineClass(scope, RhinoLucifer.class);
        Object[] arg = {};
        Scriptable myCounter = cx.newObject(scope, "RhinoLucifer", arg);
        scope.put("castimpl", scope, myCounter);
    }
}